import type {
  ChoiceStoryItem,
  DialogStoryItem,
  NarrayorStoryItem,
  StoryConfig,
  StoryItem,
  SuccessCondition,
  SuccessEvent,
} from '../../data/story/type';
import type { Condition } from '../condition-checker/type';
import type { PlayerStateSystem } from '../player-state';

// 故事引擎状态定义
export const STORY_STATE = {
  IDLE: 'IDLE',
  PLAYING: 'PLAYING',
  WAITING_FOR_UI: 'WAITING_FOR_UI',
  WAITING_FOR_CHOICE: 'WAITING_FOR_CHOICE',
  PAUSED: 'PAUSED',
  FINISHED: 'FINISHED',
} as const;

export type StoryState = (typeof STORY_STATE)[keyof typeof STORY_STATE];

// 历史记录项类型定义
export interface HistoryItem {
  itemId: string;
  type: StoryItem['type'];
  timestamp: number;
  displayText?: string[];
  speaker?: string;
  choice?: {
    index: number;
    text?: string;
  };
}

// 故事引擎回调函数接口
export interface StoryPlayerCallbacks {
  onStateChange?: (state: StoryState) => void;
  onItemStart?: (item: StoryItem) => void;
  onItemEnd?: (item: StoryItem) => void;
  onUIReadyForNext?: () => void;
  onChoicePresented?: (choiceItem: ChoiceStoryItem) => void;
  onEventsTriggered?: (events: SuccessEvent[]) => void;
  onStoryEnd?: () => void;
  onError?: (error: Error) => void;
  onHistoryUpdate?: (history: HistoryItem[]) => void;
}

/**
 * 故事引擎核心类
 * 负责管理故事流程、状态转换、用户交互和历史记录
 */
export class StoryEngine {
  private playerStateSystem: PlayerStateSystem;
  private config: StoryConfig;
  private callbacks: StoryPlayerCallbacks;

  private state: StoryState = STORY_STATE.IDLE;
  private currentItemId: string | null = null;
  private itemsMap: Map<string, StoryItem>;
  private visitedNodes: Set<string> = new Set();
  private achievedSuccessFlags: Set<string> = new Set();

  private uiResolve: (() => void) | null = null;
  private uiReject: ((error: Error) => void) | null = null;
  private history: HistoryItem[] = [];
  private choiceEvents: SuccessEvent[] = []; // 选择项的事件收集
  private successEventsTriggered: boolean = false; // 成功事件是否已触发

  constructor(
    config: StoryConfig,
    playerStateSystem: PlayerStateSystem,
    callbacks: StoryPlayerCallbacks = {}
  ) {
    this.playerStateSystem = playerStateSystem;
    this.config = config;
    this.callbacks = callbacks;

    // 构建节点映射表便于快速查找
    this.itemsMap = new Map();
    config.items.forEach((item) => {
      this.itemsMap.set(item.id, item);
    });
  }

  /**
   * 更新故事配置
   * @param newConfig 新的剧本配置
   * @param resetImmediately 是否立即重置状态
   */
  updateConfig(newConfig: StoryConfig, resetImmediately: boolean = true): void {
    this.stop();

    this.config = newConfig;
    this.itemsMap = new Map();
    newConfig.items.forEach((item) => {
      this.itemsMap.set(item.id, item);
    });

    if (resetImmediately) {
      this.resetState();
    }
  }

  /**
   * 更新回调函数
   */
  updateCallbacks(newCallbacks: StoryPlayerCallbacks): void {
    this.callbacks = newCallbacks;
  }

  /**
   * 重置引擎到初始状态
   */
  resetState(): void {
    if (this.uiReject) {
      this.uiReject(new Error('Story reset while waiting for UI'));
      this.cleanupUIWait();
    }

    this.state = STORY_STATE.IDLE;
    this.currentItemId = null;
    this.visitedNodes.clear();
    this.achievedSuccessFlags.clear();
    this.choiceEvents = [];
    this.successEventsTriggered = false;
    this.clearHistory();

    this.callbacks.onStateChange?.(this.state);
  }

  /**
   * 开始播放故事
   */
  async start(startItemId?: string): Promise<void> {
    if (
      this.state !== STORY_STATE.IDLE &&
      this.state !== STORY_STATE.FINISHED
    ) {
      throw new Error('Player is already running');
    }

    const startId = startItemId || this.config.items[0]?.id;
    if (!startId) {
      throw new Error('No start item specified and no items in config');
    }

    if (!this.itemsMap.has(startId)) {
      throw new Error(`Start item ${startId} not found`);
    }

    this.setState(STORY_STATE.PLAYING);
    this.currentItemId = startId;
    this.visitedNodes.clear();
    this.achievedSuccessFlags.clear();
    this.clearHistory();

    await this.playCurrentItem();
  }

  /**
   * 从暂停状态恢复播放
   */
  async resume(): Promise<void> {
    if (this.state !== STORY_STATE.PAUSED) {
      throw new Error('Player is not paused');
    }

    this.setState(STORY_STATE.PLAYING);

    if (this.uiResolve) {
      return;
    }

    await this.playCurrentItem();
  }

  /**
   * 暂停播放
   */
  pause(): void {
    if (
      this.state === STORY_STATE.PLAYING ||
      this.state === STORY_STATE.WAITING_FOR_UI
    ) {
      this.setState(STORY_STATE.PAUSED);
      if (this.uiReject) {
        this.uiReject(new Error('Story paused while waiting for UI'));
        this.cleanupUIWait();
      }
    }
  }

  /**
   * 停止播放
   */
  stop(): void {
    this.setState(STORY_STATE.IDLE);
    this.currentItemId = null;
    if (this.uiReject) {
      this.uiReject(new Error('Story stopped while waiting for UI'));
    }
    this.cleanupUIWait();
  }

  /**
   * UI 通知可以继续播放
   */
  notifyUIReady(): void {
    if (this.state === STORY_STATE.WAITING_FOR_UI && this.uiResolve) {
      this.uiResolve();
      this.cleanupUIWait();
    }
  }

  /**
   * 处理用户选择
   * 包含条件检查和成功标志记录
   */
  async makeChoice(choiceIndex: number): Promise<void> {
    if (this.state !== STORY_STATE.WAITING_FOR_CHOICE) {
      throw new Error('Not waiting for choice');
    }

    const currentItem = this.getCurrentItem();
    if (!currentItem || currentItem.type !== 'choice') {
      throw new Error('Current item is not a choice');
    }

    const choice = currentItem.choices[choiceIndex];
    if (!choice) {
      throw new Error(`Invalid choice index: ${choiceIndex}`);
    }

    // 检查选择条件是否满足
    const conditionPassed = this.checkCondition(choice.condition);

    this.addChoiceToHistory(currentItem as ChoiceStoryItem, choiceIndex);

    if (conditionPassed) {
      // 收集选择项的事件（不立即触发，等待故事结束时统一处理）
      if (choice.events && choice.events.length > 0) {
        this.choiceEvents.push(...choice.events);
      }

      // 记录选择成功标志
      this.recordSuccessFlag(currentItem.id, choiceIndex);

      this.setState(STORY_STATE.PLAYING);
      this.currentItemId = choice.next;
    } else {
      this.setState(STORY_STATE.PLAYING);
      if (choice.failNext) {
        this.currentItemId = choice.failNext;
      } else {
        this.endStory();
        return;
      }
    }

    await this.playCurrentItem();
  }

  /**
   * 记录成功标志（访问节点或选择选项）
   * 这个方法统一处理所有类型的成功条件记录
   */
  private recordSuccessFlag(nodeId: string, choiceIndex?: number): void {
    if (!this.config.successConditions) return;

    // 遍历所有成功条件，检查是否匹配当前节点
    this.config.successConditions.forEach((condition) => {
      if (condition.type === 'visit' && condition.nodeId === nodeId) {
        // 记录访问节点类型的成功
        this.achievedSuccessFlags.add(`${nodeId}-visit`);
      } else if (
        condition.type === 'choice' &&
        condition.nodeId === nodeId &&
        choiceIndex !== undefined &&
        condition.choiceIndex === choiceIndex
      ) {
        // 记录选择选项类型的成功
        this.achievedSuccessFlags.add(`${nodeId}-${choiceIndex}`);
      }
    });
  }

  /**
   * 检查是否应该触发成功事件
   * 只有在所有成功条件都满足且尚未触发过的情况下才返回true
   */
  private shouldTriggerSuccessEvents(): boolean {
    return !this.successEventsTriggered && this.checkAllSuccessConditions();
  }

  /**
   * 跳转到指定节点
   */
  async jumpTo(itemId: string): Promise<void> {
    if (!this.itemsMap.has(itemId)) {
      throw new Error(`Item ${itemId} not found`);
    }

    if (this.uiReject) {
      this.uiReject(new Error('Jumped to another node while waiting for UI'));
      this.cleanupUIWait();
    }

    this.setState(STORY_STATE.PLAYING);
    this.currentItemId = itemId;
    await this.playCurrentItem();
  }

  getState(): StoryState {
    return this.state;
  }

  getCurrentItem(): StoryItem | null {
    return this.currentItemId
      ? this.itemsMap.get(this.currentItemId) || null
      : null;
  }

  getHistory(): HistoryItem[] {
    return [...this.history];
  }

  getVisitedNodes(): string[] {
    return Array.from(this.visitedNodes);
  }

  hasVisitedNode(nodeId: string): boolean {
    return this.visitedNodes.has(nodeId);
  }

  getConfig(): StoryConfig {
    return this.config;
  }

  /**
   * 获取达成的成功条件
   * 将内部存储的标志转换为标准的SuccessCondition对象
   */
  getAchievedSuccessFlags(): SuccessCondition[] {
    const conditions: SuccessCondition[] = [];

    for (const flag of this.achievedSuccessFlags) {
      // 使用更安全的方式解析标志
      const lastDashIndex = flag.lastIndexOf('-');
      if (lastDashIndex === -1) {
        console.warn(`Invalid success flag format: ${flag}`);
        continue;
      }

      const nodeId = flag.substring(0, lastDashIndex);
      const typeOrIndex = flag.substring(lastDashIndex + 1);

      if (typeOrIndex === 'visit') {
        conditions.push({ type: 'visit', nodeId });
      } else {
        const choiceIndex = parseInt(typeOrIndex, 10);
        if (!isNaN(choiceIndex)) {
          conditions.push({ type: 'choice', nodeId, choiceIndex });
        } else {
          console.warn(`Invalid choice index in success flag: ${flag}`);
        }
      }
    }

    return conditions;
  }

  /**
   * 检查是否已达成所有成功条件
   */
  hasAchievedAllSuccess(): boolean {
    return this.checkAllSuccessConditions();
  }

  /**
   * 播放当前节点
   * 根据节点类型分发到不同的处理方法
   */
  private async playCurrentItem(): Promise<void> {
    if (!this.currentItemId) {
      this.endStory();
      return;
    }

    const item = this.itemsMap.get(this.currentItemId);
    if (!item) {
      this.callbacks.onError?.(
        new Error(`Item ${this.currentItemId} not found`)
      );
      this.endStory();
      return;
    }

    // 标记节点为已访问
    this.visitedNodes.add(this.currentItemId);

    // 记录访问节点的成功标志（如果有）
    this.recordSuccessFlag(this.currentItemId);

    this.callbacks.onItemStart?.(item);

    try {
      switch (item.type) {
        case 'narrator':
        case 'dialog':
          await this.playLinearItem(item);
          break;
        case 'choice':
          await this.playChoiceItem(item);
          break;
      }
    } catch (error) {
      this.callbacks.onError?.(error as Error);
      this.endStory();
    }

    this.callbacks.onItemEnd?.(item);
  }

  /**
   * 播放线性节点（旁白、对话）
   * 这些节点会自动推进到下一个节点
   */
  private async playLinearItem(
    item: NarrayorStoryItem | DialogStoryItem
  ): Promise<void> {
    this.setState(STORY_STATE.WAITING_FOR_UI);

    try {
      await this.waitForUI();
      this.addLinearItemToHistory(item);

      // 推进到下一个节点或结束故事
      if (item.next) {
        this.currentItemId = item.next;
        await this.playCurrentItem();
      } else {
        this.endStory();
      }
    } catch (error) {
      // 忽略暂停、停止、跳转等正常中断
      if (
        error instanceof Error &&
        (error.message.includes('paused') ||
          error.message.includes('stopped') ||
          error.message.includes('Jumped') ||
          error.message.includes('reset'))
      ) {
        return;
      }
      throw error;
    }
  }

  /**
   * 播放选择节点
   * 等待用户做出选择后再继续推进
   */
  private async playChoiceItem(item: ChoiceStoryItem): Promise<void> {
    this.setState(STORY_STATE.WAITING_FOR_CHOICE);
    this.callbacks.onChoicePresented?.(item);
  }

  /**
   * 等待UI响应
   * 返回一个Promise，在UI调用notifyUIReady时resolve
   */
  private waitForUI(): Promise<void> {
    return new Promise((resolve, reject) => {
      this.uiResolve = resolve;
      this.uiReject = reject;
    });
  }

  /**
   * 清理UI等待状态
   */
  private cleanupUIWait(): void {
    this.uiResolve = null;
    this.uiReject = null;
  }

  /**
   * 设置状态并触发回调
   */
  private setState(state: StoryState): void {
    this.state = state;
    this.callbacks.onStateChange?.(state);
  }

  /**
   * 结束故事
   * 统一处理所有待触发的事件并清理状态
   */
  private endStory(): void {
    const allEvents: SuccessEvent[] = [];

    // 1. 添加所有选择项事件
    allEvents.push(...this.choiceEvents);

    // 2. 如果满足成功条件，添加成功事件（只触发一次）
    if (this.shouldTriggerSuccessEvents()) {
      if (this.config.successEvents && this.config.successEvents.length > 0) {
        allEvents.push(...this.config.successEvents);
        this.successEventsTriggered = true;
      }
    }

    // 3. 统一触发所有事件
    if (allEvents.length > 0) {
      this.callbacks.onEventsTriggered?.(allEvents);
    }

    // 4. 清理选择事件
    this.choiceEvents = [];

    this.setState(STORY_STATE.FINISHED);
    this.callbacks.onStoryEnd?.();
  }

  /**
   * 检查所有成功条件是否满足
   */
  private checkAllSuccessConditions(): boolean {
    if (
      !this.config.successConditions ||
      this.config.successConditions.length === 0
    ) {
      return false;
    }

    return this.config.successConditions.every((condition) => {
      if (condition.type === 'visit') {
        // 检查是否访问过该节点
        return this.visitedNodes.has(condition.nodeId);
      } else if (condition.type === 'choice') {
        // 检查是否选择了特定选项
        return this.achievedSuccessFlags.has(
          `${condition.nodeId}-${condition.choiceIndex}`
        );
      }
      return false;
    });
  }

  /**
   * 添加线性节点到历史记录
   */
  private addLinearItemToHistory(
    item: NarrayorStoryItem | DialogStoryItem
  ): void {
    const historyItem: HistoryItem = {
      itemId: item.id,
      type: item.type,
      timestamp: Date.now(),
      displayText: item.text,
    };

    if (item.type === 'dialog') {
      historyItem.speaker = item.name;
    }

    this.history.push(historyItem);
    this.notifyHistoryUpdate();
  }

  /**
   * 添加选择结果到历史记录
   */
  private addChoiceToHistory(
    choiceItem: ChoiceStoryItem,
    choiceIndex: number
  ): void {
    const choice = choiceItem.choices[choiceIndex];
    if (!choice) return;

    const historyItem: HistoryItem = {
      itemId: choiceItem.id,
      type: 'choice',
      timestamp: Date.now(),
      choice: {
        index: choiceIndex,
        text: choice.text,
      },
    };

    this.history.push(historyItem);
    this.notifyHistoryUpdate();
  }

  /**
   * 通知历史记录更新
   */
  private notifyHistoryUpdate(): void {
    this.callbacks.onHistoryUpdate?.(this.history);
  }

  /**
   * 清空历史记录
   */
  private clearHistory(): void {
    this.history = [];
    this.notifyHistoryUpdate();
  }

  /**
   * 检查条件是否满足
   * 委托给PlayerStateSystem处理
   */
  private checkCondition(condition?: Condition[]): boolean {
    if (!condition) return true;
    return this.playerStateSystem.checkConditions(condition);
  }
}
